/**   
 * @Title: FileuploadUtil.java 
 * @Package com.ftwj.hotline.base.utils 
 * @Description: TODO(用一句话描述该文件做什么) 
 * @author guojx
 * @date Jan 4, 2019 4:37:12 PM 
 * @version V1.0   
*/
package com.example.exam.utils;


import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @ClassName: FileuploadUtil
 * @Description: 文件上传工具类
 * @author guojx
 * @version V1.0
 * @date Jan 4, 2019 4:37:12 PM
 */
public class FileuploadUtil {
	
	/**
	 * 方法描述：根据文件的绝对路径创建一个文件对象. 创建时间：2018-10-19 09:32:34
	 *
	 * @param filePath 文件的绝对路径
	 * @return 返回创建的这个文件对象
	 * @author "lixingwu"
	 */
	public static File createFile(String filePath) throws IOException {
		// 获取文件的完整目录
		String fileDir = FilenameUtils.getFullPath(filePath);
		// 判断目录是否存在，不存在就创建一个目录
		File file = new File(fileDir);
		if (!file.isDirectory()) {
			// 创建失败返回null
			if (!file.mkdirs()) {
				throw new IOException("文件目录创建失败...");
			}
		}
		// 判断这个文件是否存在，不存在就创建
		file = new File(filePath);
		if (!file.exists()) {
			if (!file.createNewFile()) {
				throw new IOException("目标文件创建失败...");
			}
		}
		return file;
	}

	/**
	 * 方法描述：判断extension中是否存在extName 创建时间：2018-10-20 20:46:18
	 *
	 * @param extension 使用逗号隔开的字符串，精确匹配例如：txt,jpg,png,zip
	 * @param extName   文件的后缀名
	 * @author "lixingwu"
	 */
	private static void isContains(String extension, String extName) {
		if (!StringUtils.isEmpty(extension)) {
			// 切割文件扩展名
			String[] exts = StringUtils.split(extension, ",");
			if (ArrayUtils.isNotEmpty(exts)) {
				assert exts != null;
				List<String> extList = Arrays.asList(exts);
				// 判断
				if (!extList.contains(extName)) {
					throw new RuntimeException("上传文件的类型只能是：" + extension);
				}
			}
			// 判断文件的后缀名是否为extension
			if (!extension.equalsIgnoreCase(extName)) {
				throw new RuntimeException("上传文件的类型只能是：" + extension);
			}
		}
	}

	/**
	 * 方法描述：处理上传的图片 创建时间：2018-10-20 20:46:18
	 *
	 * @param serverPath 图片的绝对路径
	 * @param childFile  子文件夹
	 * @param extName    文件的后缀
	 * @author "lixingwu"
	 */
	private static String thumbnails(String serverPath, String baseUploadPath, String childFile, String extName) throws IOException {
		// 压缩后的相对路径文件名
		String toFilePath = getDestPath(childFile, extName);

		// scale：图片缩放比例
		// outputQuality：图片压缩比例
		// toFile：图片位置
		// outputFormat：文件输出后缀名
		// Thumbnails 如果用来压缩 png 格式的文件，会越压越大，
		// 得把png格式的图片转换为jpg格式
		if ("png".equalsIgnoreCase(extName)) {
			// 由于outputFormat会自动在路径后加上后缀名，所以移除以前的后缀名
			String removeExtensionFilePath = FilenameUtils.removeExtension(toFilePath);
			toFilePath = removeExtensionFilePath + ".jpg";
			Thumbnails.of(serverPath).scale(1f).outputQuality(0.5f).outputFormat("jpg")
					.toFile(baseUploadPath+toFilePath);		
		} else {
			Thumbnails.of(serverPath).scale(1f).outputQuality(0.5f).toFile(baseUploadPath+toFilePath);
		}

		// 删除被压缩的文件
		FileUtils.forceDelete(new File(serverPath));

		return toFilePath;
	}

	/**
	 * 方法描述：生成文件文件名 创建时间：2018-10-20 20:46:18
	 *
	 * @param childFile 子目录
	 * @param extName   后缀名
	 * @author "lixingwu"
	 */
	private static String getDestPath(String childFile, String extName) {
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
		// 规则： 子目录/年月日_随机数.后缀名
		String sb = childFile + "/" + format.format(new Date())+"." + extName;
//		+ "_"+ Math.random()+1 + ;
		return sb;
	}

	/**
	 * 方法描述：上传文件. 创建时间：2018-10-19 13:09:19
	 *
	 * @param multipartFile 上传的文件对象，必传
	 * @param childFile     上传的父目录，为空直接上传到指定目录 （会在指定的目录下新建该目录，例如：/user/1023）
	 * @param extension     允许上传的文件后缀名，为空不限定上传的文件类型
	 *                      （使用逗号隔开的字符串，精确匹配例如：txt,jpg,png,zip）
	 * @param isImage       上传的是否是图片，如果是就会进行图片压缩；如果不希望图片被压缩，则传false，让其以文件的形式来保存
	 * @return the file result
	 * @throws IOException 异常信息应返回
	 * @author "lixingwu"
	 */
	private static Map<String,Object> saveFile(String baseUploadPath, String fileUrl, MultipartFile multipartFile, String childFile, String extension, Boolean isImage, String fileName)
			throws IOException {
		if (null == multipartFile || multipartFile.isEmpty()) {
			throw new IOException("上传的文件对象不存在...");
		}
		// 文件名
		//String fileName = multipartFile.getOriginalFilename();
		// 文件后缀名
		String extName = FilenameUtils.getExtension(fileName);
		if (StringUtils.isEmpty(extName)) {
			throw new RuntimeException("文件类型未定义不能上传...");
		}
		// 判断文件的后缀名是否符合规则
		isContains(extension, extName);
		// 创建目标文件的名称，规则请看destPath方法
		String destPath = getDestPath(childFile, extName);
		// 文件的实际路径
		String serverPath = baseUploadPath+destPath;
		// 创建文件
		File destFile = createFile(serverPath);
		// 保存文件
		multipartFile.transferTo(destFile);

		// 拼装返回的数据
		Map<String,Object> result = new HashMap<String,Object>();
		// 如果是图片，就进行图片处理
		if (BooleanUtils.isTrue(isImage)) {
			// 图片处理
			String toFilePath = thumbnails(serverPath, baseUploadPath, childFile, extName);
			// 得到处理后的图片文件对象
			File file = new File(baseUploadPath+toFilePath);
			// 压缩后的文件后缀名
			String extExtName = FilenameUtils.getExtension(toFilePath);
			// 源文件=源文件名.压缩后的后缀名
			String extFileName = FilenameUtils.getBaseName(toFilePath) + "." + FilenameUtils.getExtension(toFilePath);
			result.put("fileSize", file.length());
			result.put("fileUrl", fileUrl+toFilePath);
			result.put("serverPath", toFilePath);
			result.put("fileName", fileName);
			result.put("extName", extFileName);
			result.put("filePath", baseUploadPath+toFilePath);
		} else {
			result.put("fileUrl", fileUrl+destPath);
			result.put("fileSize", multipartFile.getSize());
			result.put("serverPath", destPath);
			result.put("fileName", fileName);
			result.put("extName", extName);
			result.put("filePath", serverPath);
		}
		return result;
	}

	/**
	 * 方法描述：上传文件. 创建时间：2018-10-19 13:09:19
	 *
	 * @param multipartFile 上传的文件对象，必传
	 * @param childFile     上传的父目录，为空直接上传到指定目录 （会在指定的目录下新建该目录，例如：/user/1023）
	 * @param extension     允许上传的文件后缀名，为空不限定上传的文件类型
	 *                      （使用逗号隔开的字符串，精确匹配例如：txt,jpg,png,zip）
	 * @return the file result
	 * @throws IOException 异常信息应返回
	 * @author "lixingwu"
	 */
	public static Map<String,Object> saveFile(String baseUploadPath, String fileUrl, MultipartFile multipartFile, String childFile, String extension, String fileName)
			throws IOException {
		return saveFile(baseUploadPath, fileUrl, multipartFile, childFile, extension, false, fileName);
	}

	/**
	 * 方法描述：上传图片. 创建时间：2018-10-19 13:09:19
	 *
	 * @param multipartFile 上传的文件对象，必传
	 * @param childFile     上传的父目录，为空直接上传到指定目录 （会在指定的目录下新建该目录，例如：/user/1023）
	 * @param extension     允许上传的文件后缀名，为空不限定上传的文件类型
	 *                      （使用逗号隔开的字符串，精确匹配例如：txt,jpg,png,zip）
	 * @return the file result
	 * @throws IOException 异常信息应返回
	 * @author "lixingwu"
	 */
	public static Map<String,Object> saveImage(String baseUploadPath, String fileUrl, MultipartFile multipartFile, String childFile, String extension, String fileName)
			throws IOException {
		return saveFile(baseUploadPath, fileUrl, multipartFile, childFile, extension, true, fileName);
	}

}
